home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
SPACE 1
/
SPACE - Library 1 - Volume 1.iso
/
program
/
168
/
mk.c
< prev
next >
Wrap
C/C++ Source or Header
|
1988-03-31
|
17KB
|
819 lines
/*
* simple make program
*
* make [options] [targets]
*
* options are
* -i ignore non-zero program returns
* -f file makefile name (default is "makefile")
* -n don't execute any commands
* -t just touch the targets, don't build
* -r ignore built-in rules
* -d debug flag (noisy output)
* -h hold the screen
*
* this program reads a makefile to build the named targets
* a makefile contains rules, macro definitions, or dependencies
* an example makefile might be:
*
* # this is a sample makefile for a spreadsheet
* OBJ = main.s io.s calc.s
* ss: $(OBJ) ss.h
* d:as.ttp d:ttp.s $(OBJ) -L d:lib.a
*
* there are built-in rules to convert .c to .s, .c to .ttp, and .c to .prg
*/
#include <stdio.h>
#define MAXLINE 160
#define MAXSYM 100
#define MAXRULE 30
#define MAXARG 75
#define TIME 0x2C
#define DATE 0x2A
#define EXEC 0x4B
#define RENAME 0x56
#define GSDTOF 0x57
#define SETDRV 0x0E
#define GETDRV 0x19
#define GETDSK 0x36
#define MALLOC 0x48
typedef struct x0 { /* structure for command lists */
char *cmd; /* pointer to the command line */
struct x0 *next; /* pointer to the next one */
} Command;
typedef struct x1 { /* structure for dependencies */
int dep; /* name of a parent */
struct x1 *next; /* pointer to next parent */
} Depend;
typedef struct { /* structure for rules */
int from; /* the extension of the parent */
int to; /* the extension of the child */
Command *cmd; /* the commands to make the child */
} Rule;
FILE *in; /* makefile input file handle */
int eof; /* eof flag for makefile input stream */
int no_exec = 0; /* don't execute the commands */
int debug = 0; /* debug output flag */
int ignore = 0; /* ignore non-zero returns */
int norules = 0; /* no built-in rules */
int hold = 1; /* hold the screen (for GEM users */
char line[MAXLINE]; /* buffer containing current input line */
char extra[MAXLINE]; /* extra buffer for macro expansion */
char name[MAXLINE]; /* space for making up names */
char *macro[MAXSYM]; /* pointer to the macros */
char *sym[MAXSYM]; /* pointer to the symbol names */
Depend *depend[MAXSYM]; /* pointer to dependencies */
Command *command[MAXSYM]; /* index into commands */
Rule rules[MAXRULE]; /* rules */
int lrule = 0; /* last rule used */
int firstsym = -1; /* what's first dependency declared */
char base[MAXLINE]; /* buffer for '*' macro */
char target[MAXLINE]; /* buffer for '@' macro */
char *save(); /* save a string */
char *alloc(); /* allocate space */
Command *cmdlist(); /* make up a command list */
Command *add_cmd(); /* add a command to a command list */
long date(); /* get the date of a file */
char *av[MAXARG]; /* argv for built-in's */
int ac; /* argc for built-in's */
FILE *xin; /* stdin for built-in commands */
FILE *xout; /* stdout for built-in commands */
main(argc, argv) char *argv[]; {
int i, err, tch;
char *name;
i = 1;
name = "makefile";
tch = err = 0;
for (i = 1; i < argc && *argv[i] == '-'; i++) {
switch (argv[i][1]) {
case 'f': case 'F':
i++;
name = argv[i];
break;
case 'i': case 'I':
ignore = 1;
break;
case 'd': case 'D':
debug = 1;
break;
case 't': case 'T':
tch = 1;
break;
case 'n': case 'N':
no_exec = 1;
break;
case 'r': case 'R':
norules = 1;
break;
case 'h': case 'H':
hold = !hold;
break;
default:
printf("unknown option: %s\n", argv[i]);
err = 1;
break;
}
}
if (err) error("usage: make [-i -n -t -r -d -h -f file] [targets]\n");
if (tch) {
while (i < argc)
touch(argv[i++]);
}
else {
init();
input(name);
if (i == argc && firstsym >= 0)
make(firstsym);
else {
for ( ; i < argc; i++)
if (!assign(argv[i]))
make(lookup(argv[i]));
}
}
bye(0);
}
/* initialize the symbol table and add built-in rules */
init() {
int i;
Command *cp;
rules[0].cmd = NULL;
for (i = 0; i < MAXSYM; i++)
sym[i] = NULL;
if (norules) return;
/* built-in rules */
cp = NULL;
cp = add_cmd(cp, " d:\\cc.ttp $*.c");
cp = add_cmd(cp, " d:\\as.ttp -o $*.ttp d:\\ttp.s yc.out -L d:\\lib.a");
cp = add_cmd(cp, " rm yc.out");
add_rule(".c", ".ttp", cp);
cp = NULL;
cp = add_cmd(cp, " d:\\cc.ttp $*.c");
cp = add_cmd(cp,
" d:\\as.ttp -o $*.prg d:\\prg.s yc.out -L d:\\gem.a d:\\lib.a");
cp = add_cmd(cp, " rm yc.out");
add_rule(".c", ".prg", cp);
cp = NULL;
cp = add_cmd(cp, " d:\\cc.ttp -o $*.s $*.c");
add_rule(".c", ".s", cp);
}
/* read in and parse the makefile */
input(name) char *name; {
if (!findfile(name))
return;
getline();
while (!eof) {
if (*line == '#')
getline();
else if (macdef())
getline();
else if (*line == '.')
rule();
else if (*line > ' ')
dependency();
else getline();
}
fclose(in);
}
/* search high and low for a makefile */
findfile(name) char *name; {
int i, drv, r;
/* someday, turn a full pathname into a chdir */
if (in = fopen(name, "r")) /* try current directory first */
return 1;
drv = trap(1, GETDRV);
for (i = 0; i < 4; i++) { /* try A:, B:, C:, D: */
r = trap(1, SETDRV, i);
if (in = fopen(name, "r")) {
printf(" run from %c:\n", i + 'A');
return 1;
}
}
trap(1, SETDRV, drv);
return 0;
}
/* read in a line from the makefile */
getline() {
int c;
char *l;
l = line;
c = getch();
while (c != EOF && c != '\n') {
if (c == '\\') {
if ((c = getch()) == '\n')
c = ' ';
else *l++ = '\\';
}
*l++ = c;
if (c <= ' ') { /* skip spaces */
while (c != EOF && c != '\n' && c <= ' ')
c = getch();
}
else c = getch();
}
*l = 0;
eof = (c == EOF);
}
/* get a character from the file, strip out '\r' */
getch() {
int c;
while ((c = getc(in)) == '\r')
;
return c;
}
/* expand all the macro's in the current line */
expand() {
int done;
char *e, *l, *m;
while (1) {
e = extra;
l = line;
done = 1;
while (*e++ = *l++)
if (*l == '$')
done = 0;
if (done)
break;
e = extra;
l = line;
while (*e) {
if (*e == '$') {
e++;
m = name;
if (*e == '(') { /* multi letter macro */
e++;
while (*e != ')')
*m++ = *e++;
e++;
}
else *m++ = *e++; /* one letter macro */
*m = 0;
if (m = macro[lookup(name)]) {
while (*m)
*l++ = *m++;
}
else error("$(%s) not defined", name);
}
else *l++ = *e++;
}
*l = 0;
}
}
/* read in a rule, ".from.to:" followed by command lines */
rule() {
int i, j;
char to[10], from[10], *l;
l = line;
i = j = 0;
if (*l != '.')
error("bad rule entry");
do { from[j++] = *l++; } while (*l && *l != '.');
from[j] = 0;
if (*l != '.')
error("bad rule entry");
j = 0;
do { to[j++] = *l++; } while (*l && *l != ':');
to[j] = 0;
add_rule(from, to, cmdlist());
}
/* build a list of commands, return pointer to them */
Command *
cmdlist() {
Command *r;
r = NULL;
getline();
while (*line && *line <= ' ') {
r = add_cmd(r, save(line));
getline();
}
return r;
}
/* check for a command line macro def and process if there */
assign(s) char *s; {
char *p;
for (p = s; *p && *p != '='; p++)
;
if (*p == '=') {
*p++ = 0;
add_mac(s, save(p));
return 1;
}
else return 0;
}
/* check for a macro def and process if there */
macdef() {
char *l, *b, *e;
l = line;
while (*l && *l <= ' ') l++;
b = l;
while (*l && *l > ' ') l++;
e = l;
while (*l && *l <= ' ') l++;
if (*l++ == '=') { /* got a macro */
*e = 0;
add_mac(b, save(l));
return 1;
}
else return 0;
}
/* parse a dependency, "child [children]*: [parents]*" */
dependency() {
int i, j, target[20], depend[20];
Command *cmd;
expand();
i = namelist(target, 0);
if (line[i] != ':')
error("bad dependency rule");
i = namelist(depend, i+1);
cmd = cmdlist();
for (i = 0; target[i]; i++) {
for (j = 0; depend[j]; j++)
add_dep(target[i], depend[j]);
set_cmd(target[i], cmd);
}
if (firstsym < 0)
firstsym = target[0];
}
/* gather up a list of names in the input line */
namelist(list, i) int *list; {
int t, j;
t = 0;
while (line[i] && line[i] != ':') {
while (line[i] && line[i] <= ' ')
i++;
j = 0;
if (line[i]) {
while (line[i] && line[i] > ' ' && line[i] != ':')
name[j++] = line[i++];
name[j] = 0;
list[t++] = lookup(name);
}
}
list[t] = 0;
return i;
}
/* add a new command to the end of a command list */
Command *
add_cmd(cp, cmd) Command *cp; char *cmd; {
Command *p, *r;
p = alloc((short)sizeof(Command));
p->cmd = cmd;
p->next = NULL;
if (cp == NULL)
r = p;
else {
r = cp;
while (cp->next)
cp = cp->next;
cp->next = p;
}
return r;
}
/* add a parent (target) to a child (dependency) */
add_dep(target, dep) {
Depend *p;
if (debug) printf("add_dep(%s,%s)\n", sym[target], sym[dep]);
p = alloc((short)sizeof(Depend));
p->dep = dep;
p->next = depend[target];
depend[target] = p;
}
/* add a macro */
add_mac(name, str) char *name, *str; {
if (debug) printf("add_mac(%s,%s)\n", name, str);
macro[lookup(name)] = str;
}
/* add a command list to a target */
set_cmd(target, cp) Command *cp; {
if (debug) printf("set_cmd(%s,%lx)\n", sym[target], cp);
command[target] = cp;
}
/* add a rule */
add_rule(from, to, cp) char *from, *to; Command *cp; {
if (debug) printf("add_rule(%s,%s,%lx)\n", from, to, cp);
rules[lrule].from = lookup(from);
rules[lrule].to = lookup(to);
rules[lrule].cmd = cp;
if (++lrule >= MAXRULE)
error("too many rules");
rules[lrule].cmd = NULL;
}
/* build a child by first building the parents */
make(child) {
int mkflag;
long chdate;
Command *cp;
Depend *dp;
if (debug) printf("make(%s)\n", sym[child]);
chdate = date(sym[child]);
mkflag = 0;
if (dp = depend[child]) {
while (dp) {
make(dp->dep);
if (check(dp->dep, chdate))
mkflag = 1;
dp = dp->next;
}
}
else mkflag = 1;
if (mkflag) {
strcpy(target, sym[child]);
add_mac("@", target);
if (cp = command[child]) {
unlink(target);
execute(cp);
}
else chkrule(child, chdate);
}
}
/* set the date/time of the named file to the present */
touch(name) char *name; {
int fd, r;
long dt;
if ((fd = open(name, 2)) >= 0) {
dt = (trap(1, DATE) && 0xFFFF) | (trap(1, TIME) << 16);
if (r = trap(1, GSDTOF, &dt, fd, 1))
perror(r, name);
close(fd);
}
else error("cannot open %s (%d)\n", name, fd);
}
/* get the date/time of the named file */
long
date(name) char *name; {
int fd;
unsigned long dt;
if ((fd = open(name, 0)) >= 0) {
trap(1, GSDTOF, &dt, fd, 0);
dt = ((dt >> 16) & 0xFFFFL) | (dt << 16); /* swap words */
close(fd);
}
else dt = 0L;
if (debug) printf("date of %s is %lx\n", name, dt);
return dt;
}
/* compare the date/time of the named file against the child date */
check(parent, chdt) long chdt; {
long pardt;
pardt = date(sym[parent]);
return (pardt > chdt);
}
/* see if there are any rules that we can use to build the child */
chkrule(child, chdate) long chdate; {
Rule *r;
char *s, *e;
int i, j, ext, parent, parbase;
s = sym[child];
for (j = i = 0; base[i] = s[i]; i++)
if (s[i] == '.')
j = i;
if (j == 0)
return 0;
e = &s[j];
base[j] = 0;
parbase = lookup(base);
ext = lookup(e);
for (i = lrule; --i >= 0; ) {
r = &rules[i];
if (r->to == ext) {
strcpy(extra, base);
strcat(extra, sym[r->from]);
parent = lookup(extra);
make(parent);
add_mac("*", sym[parbase]);
if (check(parent, chdate)) {
unlink(sym[child]);
execute(r->cmd);
return;
}
}
}
}
/* execute a list of commands */
execute(cp) Command *cp; {
int r;
while (cp) {
strcpy(line, cp->cmd);
expand();
printf(" %s\n", line);
if (!no_exec && (r = system(line)) && !ignore)
perror(r, "command failed");
cp = cp->next;
}
}
/* do something, either built-in (rm, mv) or exec a program */
args(s) char *s; { /* built and argc, argv for the built-in's */
char *strtok();
ac = 1;
s = strtok(s, " \t");
xin = stdin;
xout = stdout;
while (ac < MAXARG && s != NULL) {
if (*s == '>') {
if (s[1] == '>')
xout = fopen(s+2, "a");
else xout = fopen(s+1, "w");
}
else if (*s == '<')
xin = fopen(s+1, "r");
else av[ac++] = s;
s = strtok(NULL, " \t");
}
av[ac] = NULL;
}
rm() { /* remove a file */
int i, r, rr;
rr = 0;
for (i = 1; i < ac; i++) {
if ((r = unlink(av[i])) != 0 && r != -33) {
/* not deleted but was found */
perror(r, av[i]);
rr = r;
}
}
return rr;
}
mv() { /* rename a file */
int r;
if (ac == 3) {
unlink(av[2]);
if (r = trap(1, RENAME, 0, av[1], av[2])) {
printf("rename didn't work (%d), try copy\n", r);
if ((r = cp()) == 0)
unlink(av[1]);
}
}
return r;
}
cp() { /* copy a file */
int r;
FILE *in, *out;
r = 1;
if (ac == 3) {
if (in = fopen(av[1], "rb")) {
if (out = fopen(av[2], "wb")) {
xcat(in, out);
r = 0;
fclose(in);
fclose(out);
}
else error("cannot create %s\n", av[2]);
fclose(in);
}
else error("cannot copy %s\n", av[1]);
}
return r;
}
cat() { /* cat a file */
int i, r;
FILE *in;
r = 0;
for (i = 1; i < ac; i++) {
if ((in = fopen(av[i], "r")) == NULL) {
r = 1;
error("cannot cat %s", av[i]);
}
else xcat(in, xout);
}
return r;
}
xcat(i, o) FILE *i, *o; { /* do the real work of cat */
int c;
while ((c = getc(i)) != EOF)
putc(c, o);
fclose(i);
}
grep() {
int i;
char *p, *fgets();
FILE *in, *fopen();
strlower(p = av[1]);
for (i = 2; i < ac; i++) {
if (in = fopen(av[i], "r")) {
while (fgets(extra, MAXLINE, in)) {
strlower(extra);
if (match(p, extra))
printf("%s:\t%s", av[i], extra);
}
fclose(in);
}
else printf("cannot open %s\n", av[i]);
}
return 0;
}
match(pat, line) char *pat, *line; {
char *p, *l;
while (*line) {
p = pat;
l = line++;
while (*p++ == *l++)
if (*p == 0)
return 1;
}
return 0;
}
xfree() {
long m, dsz[4];
int c, drv;
if (ac > 1 && (c = *av[1]) >= 'A' && c <= 'P')
drv = c - 'A';
else drv = trap(1, GETDRV);
trap(1, GETDSK, dsz, drv + 1);
m = trap(1, MALLOC, -1L);
printf("%ld free bytes in memory, ", m);
printf("%ld free bytes on %c:\n", dsz[0]*dsz[2]*dsz[3], drv+'A');
return 0;
}
struct bltin {
char *name;
int (*func)();
} btbl[] = {
{ "rm", rm },
{ "mv", mv },
{ "cp", cp },
{ "cat", cat },
{ "grep", grep },
{ "free", xfree },
{ NULL, NULL }
};
system(s) char *s; {
int i, r;
char *p;
while (*s && *s <= ' ')
s++;
for (p = extra; *s && *s > ' '; )
*p++ = *s++;
*p = 0;
for (i = 0; btbl[i].name != NULL; i++) {
if (strcmp(extra, btbl[i].name) == 0) {
args(s);
r = (*btbl[i].func)();
if (xin != stdin)
fclose(xin);
if (xout != stdout)
fclose(xout);
return r;
}
}
if ((r = strlen(s+1)) >= 128)
error("command line too long");
else {
*s = r;
r = trap(1, EXEC, 0, extra, s, "");
}
return r;
}
/* symbol table lookup */
lookup(s) char *s; {
int i, start;
upper(s); /* too bad TOS filenames are always uppercase */
start = i = *s;
while (sym[i]) {
if (strcmp(s, sym[i]) == 0)
return i;
if (++i >= MAXSYM)
i = 0;
if (i == start)
error("too many symbols");
}
sym[i] = save(s);
command[i] = macro[i] = depend[i] = 0L;
return i;
}
/* convert a string to all uppercase in place */
upper(s) char *s; {
register int c;
for ( ; c = *s; s++) {
if (c >= 'a' && c <= 'z')
*s = c - 'a' + 'A';
}
}
/* save a string */
char *
save(s) char *s; {
char *r, *alloc();
r = alloc(strlen(s)+1);
strcpy(r, s);
return r;
}
/* allocate some space */
char *
alloc(n) {
char *r, *malloc();
if ((r = malloc(n)) == NULL)
error("out of free space");
return r;
}
bye(n) {
if (hold) {
printf("(press any char)\n");
getchar();
}
exit(n);
}
perror(r, s) char *s; {
char *p;
switch (r) {
case -32: p = "invalid function number"; break;
case -33: p = "file not found"; break;
case -34: p = "pathname not found"; break;
case -35: p = "too many open files"; break;
case -36: p = "access not possible"; break;
case -37: p = "invalid handle"; break;
case -39: p = "not enough memory"; break;
case -46: p = "invalid drive spec"; break;
case -49: p = "no more files"; break;
default: sprintf(p = extra, "error %d", r);
}
error("%s: %s", p, s);
}
/* complain and get out */
error(s, a, b, c, d) char *s; long a, b, c, d; {
printf("** ");
printf(s, a, b, c, d);
printf("\n");
bye(1);
}